#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "iot_gpio.h"
#include "hi_io.h"
#include "iot_gpio.h"
#include <sys/time.h>
#include <sys/types.h>
#include <stddef.h>
#include "net_demo.h"
#include "net_common.h"

#include "sg92.h"
#include "GasDetection.h"

#define RED_GPIO_10 10
#define GREEN_GPIO_11 11
#define BLUE_GPIO_12 12

#define PWM_PORT_NUM1 (1)
#define PWM_PORT_NUM2 (2)
#define PWM_PORT_NUM3 (3)

#define PIR_GPIO_7 7
#define YELLOW_LED_GPIO_8 8

#define IOT_IO_NAME_GPIO_2 2 // 舵机控制引脚
// 红灯和绿色表示工作状态
#define RED_GPIO_0 0
#define GREEN_GPIO_1 1

#define GPIO_HIGH (1)
#define GPIO_LOW (0)

static char request[] = "choice:clothes gas";
// static char door_request[] = "choice: open close break";
// static char light_request[] = "choice: red green blue close break";
// static char PIR_request[128] = "choice:PIRopen PIRclose";
static char response[128] = "";
static char light_intensity[128] = "";
// static int result;
static int intensity;

#define DELAY_1S (1)

void TcpServerTest(unsigned short port)
{
    ssize_t retval = 0;
    int backlog = 1;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
    int connfd = -1;

    struct sockaddr_in clientAddr = {0};
    socklen_t clientAddrLen = sizeof(clientAddr);
    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);              // 端口号，从主机字节序转为网络字节序
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入， 0.0.0.0

    retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // 绑定端口
    if (retval < 0)
    {
        printf("bind failed, %ld!\r\n", retval);
        close(sockfd);
    }
    printf("bind to port %hu success!\r\n", port);

    retval = listen(sockfd, backlog); // 开始监听
    if (retval < 0)
    {
        printf("listen failed!\r\n");
        close(sockfd);
    }
    printf("listen with %d backlog success!\r\n", backlog);

    // 接受客户端连接，成功会返回一个表示连接的 socket ， clientAddr 参数将会携带客户端主机和端口信息 ；失败返回 -1
    // 此后的 收、发 都在 表示连接的 socket 上进行；之后 sockfd 依然可以继续接受其他客户端的连接，
    //  UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接，父进程继续接受其他客户端的连接
    //  鸿蒙liteos-a内核之上，可以使用UNIX的“每个连接一个进程”的并发模型
    //     liteos-m内核之上，可以使用“每个连接一个线程”的并发模型
    connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
    if (connfd < 0)
    {
        printf("accept failed, %d, %d\r\n", connfd, errno);
        close(sockfd);
    }
    printf("accept success, connfd = %d!\r\n", connfd);
    printf("client addr info: host = %s, port = %hu\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));

    while (1)
    {
        // 建立连接成功之后，这个TCP socket描述符 —— sockfd 就具有了 “连接状态”，
        // 发送、接收 对端都是 connect 参数指定的目标主机和端口
        retval = send(connfd, request, strlen(request), 0);
        if (retval < 0)
        {
            printf("send request failed!\r\n");
        }
        printf("send request{%s} %ld to server done!\r\n", request, retval);

        retval = recv(connfd, response, sizeof(response), 0);
        if (retval <= 0)
        {
            printf("send response from server failed or done, %ld!\r\n", retval);
        }
        response[retval] = '\0';
        printf("recv response{%s} %ld from server done!\r\n", response);

        // 晾衣架
        if (strcmp(response, "clothes") == 0)
        {
            printf("clothes\r\n");
            while (1)
            {
                static int state;
                memset(response, 0, sizeof(response));
                recv(connfd, response, sizeof(response), 0);
                printf("recv response{%s} %ld from server done!\r\n", response);
                if (strcmp(response, "extend") == 0)
                {
                    printf("extend\r\n");
                    if (state == 1)
                    {
                        send(connfd, "The clothes drying pole has been extended!\r\n", sizeof("The clothes drying pole has been extended!"), 0);
                        printf("The door is already open!\r\n");
                        memset(response, 0, sizeof(response));
                        continue;
                    }
                    else
                    {
                        state = ExtendTask(connfd);
                    }
                }
                else if (strcmp(response, "shorten") == 0)
                {
                    printf("shorten\r\n");
                    if (state == 0)
                    {
                        send(connfd, "The clothes drying pole has been shortened!\r\n", sizeof("The clothes drying pole has been shortened!"), 0);
                        printf("The door is already closed!\r\n");
                        memset(response, 0, sizeof(response));
                        continue;
                    }
                    else
                    {
                        state = ShortenTask(connfd);
                    }
                }
                else if (strcmp(response, "break") == 0)
                {
                    printf("break\r\n");
                    memset(response, 0, sizeof(response));
                    break;
                }
            }
        }
        else if (strcmp(response, "gas") == 0)
        {
            printf("gas\r\n");
            fd_set read_fds;
            struct timeval timeout;
            int max_fd = connfd; // 假设connfd是你想要监视的文件描述符
            char buffer[100];
            memset(buffer, 0, sizeof(buffer));

            while (1)
            {
                FD_ZERO(&read_fds);
                FD_SET(connfd, &read_fds); // 将网络连接的文件描述符添加到要监视的集合中

                // 设置超时时间，这里设置为1秒，可根据实际情况调整
                timeout.tv_sec = 1;
                timeout.tv_usec = 0;

                // 调用select函数进行监视，等待connfd有可读数据或者超时
                int ret = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);

                if (ret == -1)
                {
                    perror("select error");
                    return 1;
                }
                else if (ret == 0)
                {

                    // 超时情况，继续执行正常的循环任务
                    GasDetection_Task(connfd);
                }
                else
                {
                    // 当select返回且connfd可读时，说明有输入了，去获取输入内容并判断
                    if (FD_ISSET(connfd, &read_fds))
                    {
                        // 使用recv获取输入内容
                        ssize_t bytes_received = recv(connfd, buffer, sizeof(buffer) - 1, 0);
                        if (bytes_received <= 0)
                        {
                            // 连接关闭或错误
                            break;
                        }

                        // 确保字符串以null结尾
                        buffer[bytes_received] = '\0';

                        // 去除字符串末尾的换行符（如果有的话）
                        if (buffer[strlen(buffer) - 1] == '\n')
                        {
                            buffer[strlen(buffer) - 1] = '\0';
                        }

                        // 检查接收到的命令
                        if (strcmp(buffer, "break") == 0)
                        {
                            printf("break\r\n");
                            break;
                        }
                    }
                }
            }
        }
        memset(response, 0, sizeof(response));
    }
}

void SmartHomeTask(void)
{
    hi_gpio_init();
    // 晾衣架
    hi_io_set_func(IOT_IO_NAME_GPIO_2, HI_IO_FUNC_GPIO_2_GPIO);
    hi_io_set_func(GREEN_GPIO_1, 0);
    hi_io_set_func(RED_GPIO_0, 0);
    IoTGpioSetDir(IOT_IO_NAME_GPIO_2, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(RED_GPIO_0, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(GREEN_GPIO_1, IOT_GPIO_DIR_OUT);
}

SYS_RUN(SmartHomeTask);

SERVER_TEST_DEMO(TcpServerTest);